# -*- coding: utf-8 -*-
"""
模型描述
f1=

"""
import numpy as np
from sympy.abc import *
import geatpy as ea
import sympy


class MaintainProblem(ea.Problem):  # 继承Problem父类
    yearTotal = 0
    feeLimit = 0
    roadLen = 0
    roadSectionTotal = 0
    roadSections = []  # 路段数组

    def __init__(self, yearTotal=5, feeLimit=8000 * 10000, roadLen=309):
        self.yearTotal = yearTotal
        self.feeLimit = feeLimit
        self.roadLen = roadLen * 1000
        if (self.roadLen % 1000 > 0):  # 公里数有小数,就多划分一个路段
            temp = int(self.roadLen / 1000) + 1
            self.roadSectionTotal = int(self.roadLen / 1000) + 1
            self.roadSections = np.full(self.roadSectionTotal, 1000, dtype=float)
            self.roadSections[self.roadSectionTotal - 1] = self.roadLen % 1000  # 最后一个路段长度为公里的小数
        # 路面指标系数
        M = 3  # 决策函数个数
        name = 'MaintainProblem'  # 初始化name（函数名称，可以随意设置）
        Dim = 9  # 初始化Dim（决策变量维数）共9个决策变量
        maxormins = [-1, 1, 1]  # 初始化maxormins（目标最小最大化标记列表，1：最小化该目标；-1：最大化该目标）
        varTypes = [0, 0, 0, 0, 0, 1, 1, 1, 1]  # 初始化varTypes（决策变量的类型，0：实数；1：整数）
        lb = [85, 85, 85, 85, 85, 0, 0, 0, 0]  # 决策变量下界,前5个为养护指标下界,后面4个分别为养护类型,是否采用养护类型,年份,路段数组起始下标
        ub = [100, 100, 100, 100, 100, 7, 1, 4, self.roadSectionTotal - 1]  # 决策变量上界
        lbin = [1] * Dim  # 决策变量下边界（0表示不包含该变量的下边界，1表示包含）
        ubin = [1] * Dim  # 决策变量上边界（0表示不包含该变量的上边界，1表示包含）
        # 调用父类构造方法完成实例化
        ea.Problem.__init__(self,
                            name,
                            M,
                            maxormins,
                            Dim,
                            varTypes,
                            lb,
                            ub,
                            lbin,
                            ubin)

    def evalVars(self, Vars):  # 目标函数
        pci = Vars[:, [0]]
        rqi = Vars[:, [1]]
        rdi = Vars[:, [2]]
        pbi = Vars[:, [3]]
        sri = Vars[:, [4]]
        maintainTypeIndex = Vars[:, [5]]  # 养护类型
        ifTypeIndex = Vars[:, [6]]  # 是否选择养护某一类型
        yearIndex = Vars[:, [7]]  # 年份下标变量
        sectionIndex = Vars[:, [8]]  # 路段下标变量
        # 年份数组 决策期为5年
        years = np.full(self.yearTotal, 1, dtype=int)

        wPCI = 0.35
        wRQI = 0.30
        wRDI = 0.15
        wPBI = 0.10
        wSRI = 0.10
        # 路面性能指标计算
        pqi = wPCI * pci + wRQI * rqi + wRDI * rdi + wPBI * pbi + wSRI * sri

        # 年份决策变量转换,将传入的决策变量年份下标数组,转换为具体的年份数组
        yearArr = self.convertArr(yearIndex, years)
        roadSectionArr = self.convertArr(sectionIndex, self.roadSections)
        # 第一个决策函数,性能指标
        # 函数核心
        # 年份和路段区间内的累加
        f1 = self.f1core(pqi, roadSectionArr)
        print(f1)
        # 第二个函数
        # 最小养护费用
        # n = sympy.Symbol('n') #养护的类型变量
        maintainFees = [0, 18.7, 53, 82, 80, 168, 280, 520]  # 八种养护类型的费用单价 每平方米
        ifType = [0, 1]
        ifTypeArr = self.convertArr(ifTypeIndex, ifType)
        maintainFeeArr = self.convertArr(maintainTypeIndex, maintainFees)
        f2 = self.f2core(maintainFeeArr, roadSectionArr)  # 调用费用函数
        print("f2:%f" % (f2))

        # 第三个函数
        # 最小碳排放量
        maintainCarbons = [0, 0.23, 0.8, 0.92, 1.44, 1.54, 1.60, 1.64]  # #八种养护类型的碳排放量 每平方米
        maintainCarbonArr = self.convertArr(maintainTypeIndex, maintainCarbons)
        f3 = self.f3core(maintainCarbonArr, roadSectionArr)  # 调用费用函数

        # 利用可行性法则处理约束条件
        CV = np.hstack([
            self.feeLimit - f1  # 约束条件 总体养护费用小于等于养护费用上线
        ])
        f = np.hstack([f1, f2, f3])
        return f, CV

    def convertArr(self, inArr, varsArr):
        i = 0
        j = 0
        outArr = inArr.copy()
        for x in inArr:
            for y in x:
                outArr[i][j] = varsArr[int(y)]
                j += 1
            j = 0
            i += 1
        return outArr

    # ***********************************
    # 第一个决策函数,函数核心 性能指标
    # t 年份,i 路段编号
    # 年份和路段区间内的指标性能累加
    # ************************************
    def f1core(self, pqi, roadSectionArr):
        result = 0
        t = 0
        while t < self.yearTotal:
            for i in range(0, len(roadSectionArr)):
                result += pqi * (roadSectionArr[i] / self.roadLen)
            t += 1
        return result

    # ***********************************
    # 第二个决策函数函数核心,费用指标
    # t 年份,i 路段编号,j 养护类型编号
    # 年份和路段区间内的各种养护方案的费用之和
    # ************************************
    def f2core(self, maintainFeeArr, roadSectionArr):
        result = 0
        t = 0  # 年份
        maintainType = dict()
        while t < self.yearTotal:
            for i in range(0, len(roadSectionArr)):
                for j in range(0, len(maintainFeeArr)):
                    key = '{}_{}_{}'.format(t, i, j)
                    if maintainType.get(key) == None:
                        result += roadSectionArr[i] * maintainFeeArr[j] * 25
                        maintainType.update({key: 1})
            t += 1
        return result

    # ***********************************
    # 第三个决策函数函数核心,碳排放指标
    # t 年份,i 路段编号,j 养护类型编号
    # 年份和路段区间内的各种养护方案的碳排放之和
    # ************************************
    def f3core(self, maintainCarbons, roadSectionArr):
        # ifTypeArr*maintainFeeArr*yearArr*roadSectionArr*25
        result = 0
        t = 0
        maintainType = dict()
        while t < self.yearTotal:
            for i in range(0, len(roadSectionArr)):
                for j in range(0, len(maintainCarbons)):
                    key = '{}_{}_{}'.format(t, i, j)
                    if maintainType.get(key) == None:
                        result += roadSectionArr[i] * maintainCarbons[j] * 25
                        maintainType.update({key: 1})
            t += 1
        return result
